﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LitJson;

[AddComponentMenu("PUEX/Affector/Physics/ForceAffector")]
public class PUEXForceAffector : PUEXAffector {

	#region - Editable property
	public Vector3 center;
	public string centerParamName = "";
	public Vector3 size;
	public string sizeParamName = "";
	public Vector3 force;
	public string forceParamName = "";
	public bool inWorldSpace;
	public bool applyOwnerScale;
	#endregion

	#region - Property
	protected Bounds _bounds;
	protected Vector3 _force;
	#endregion
	
	#region - Lifecycle
	public PUEXForceAffector ()
	{
		center = Vector3.zero;
		size = new Vector3 (20f, 20f, 20f);
		force = Vector3.forward * 2f;
		inWorldSpace = true;
		applyOwnerScale = true;
	}
	#endregion
	
	#region - Update
	public override void preUpdate (float dt)
	{
		base.preUpdate (dt);

		Vector3 center_ = center;
		Vector3 size_ = size;
		Vector3 forceDir_ = force.normalized;
		float forceMag_ = force.magnitude;
		if (inWorldSpace) {
			if (ownerEmitter.keepLocal) {
				Matrix4x4 invMat = ownerEmitter.ownerParticleSystem.systemToWorldTransform.inverse;
				center_ = invMat.MultiplyPoint(center_);
				Vector3 s = ownerEmitter.ownerParticleSystem.systemToWorldScale3;
				s = new Vector3 (1f / s.x, 1f / s.y, 1f / s.z);
				size_.Scale(s);
				forceDir_ = invMat.MultiplyVector(forceDir_);
			}
		} else {
			if (!ownerEmitter.keepLocal) {
				center_ = ownerEmitter.ownerParticleSystem.systemToWorldTransform.MultiplyPoint(center_);
				size_.Scale(ownerEmitter.ownerParticleSystem.systemToWorldScale3);
				forceDir_ = ownerEmitter.ownerParticleSystem.systemToWorldTransform.MultiplyVector(forceDir_);
			}
		}
		_bounds = new Bounds (center_, size_);

		if (applyOwnerScale) {
			forceMag_ *= ownerEmitter.ownerParticleSystem.systemToWorldScale;
		}
		_force = forceDir_ * forceMag_;
	}

	public override void update (float dt, PUEXParticle particle)
	{
		if (_bounds.Contains (particle.position)) {
			Vector3 velocity = particle.velocity() + _force * particle.mass * dt;
			particle.setVelocity (velocity);
		}
	}
	#endregion
	
	#region - Param property
	public override void updateParams (PUEXParticleSystem system)
	{
		Vector3 value;
		if (system.getParamVec3 (centerParamName, out value)) {
			center = value;
		}
		if (system.getParamVec3 (sizeParamName, out value)) {
			size = value;
		}
		if (system.getParamVec3 (forceParamName, out value)) {
			force = value;
		}
	}
	#endregion
	
	#region - Draw
	public void OnDrawGizmos()
	{
		if (!enabled)
			return;

		Matrix4x4 defaultMatrix = Gizmos.matrix;
		if (inWorldSpace) {
			Gizmos.matrix = Matrix4x4.identity;
		} else {
			Gizmos.matrix = transform.parent.transform.localToWorldMatrix;
		}
		
		Color defaultColor = Gizmos.color;
		Gizmos.color = Color.yellow;
		
		Gizmos.DrawWireCube (center, size);
		
		Gizmos.color = defaultColor;
		Gizmos.matrix = defaultMatrix;
	}
	#endregion

	#region - Serialization
	public override JsonData save (JsonData emitterData, JsonData systemData)
	{
		JsonData ret = base.save (emitterData, systemData);

		ret ["center"] = PUEXUtils.serializeVector3 (center);
		ret ["center_param_name"] = centerParamName;
		ret ["size"] = PUEXUtils.serializeVector3 (size);
		ret ["size_param_name"] = sizeParamName;
		ret ["force"] = PUEXUtils.serializeVector3 (force);
		ret ["force_param_name"] = forceParamName;
		ret ["in_world_space"] = inWorldSpace;
		ret ["apply_owner_scale"] = applyOwnerScale;
		
		return ret;
	}
	#endregion

}
